package com.yungu.swift.order.helper;

import com.alibaba.dubbo.config.annotation.Reference;
import com.yungu.swift.assets.driver.model.dto.CarModelValuationDto;
import com.yungu.swift.constants.CommonConstant;
import com.yungu.swift.constants.OrderConstant;
import com.yungu.swift.order.model.dto.CommissionDto;
import com.yungu.swift.order.model.dto.OrderFareDto;
import com.yungu.swift.order.model.vo.OrderCostItemVo;
import com.yungu.swift.system.sys.model.dto.SysBusinessOrganizationDto;
import com.yungu.swift.system.sys.service.SysBusinessOrganizationService;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 预估费用计算类
 *
 * @author Zoro
 * @since 2016/10/15
 */
public class EstimatedFareHelper {
    /**
     * 计费方式
     */
    private CarModelValuationDto billingWay;
    /**
     * 行驶里程
     */
    private Double planMileage;
    /**
     * 行驶时长
     */
    private Integer planDuration;
    /**
     * 用来计算高峰溢价和夜间费的时间点
     */
    private Date pointTime;
    /**
     * 总费用
     */
    private Double totalFee = 0d;

    /**
     * 费用明细
     */
    private OrderFareDto costDetail = new OrderFareDto();

    @Reference
    private SysBusinessOrganizationService sysBusinessOrganizationService;


    public EstimatedFareHelper(CarModelValuationDto billingWay, Double planMileage, Integer planDuration, Date pointTime) {
        this.billingWay = billingWay;
        this.planMileage = planMileage;
        this.planDuration = planDuration;
        this.pointTime = pointTime;
    }

    /**
     * 获取明细
     */
    public OrderFareDto getCostDetail() {
        return costDetail;
    }

    /**
     * 获取总费用
     */
    public Double getTotalFee() {
        return getDoubleValue(totalFee, 2);
    }

    /**
     * 添加总里程总时长
     */
    public EstimatedFareHelper addTrip() {
        costDetail.setTripDistance(planMileage);
        costDetail.setTripDuration(planDuration);
        return this;
    }

    /**
     * 添加起步费
     */
    public EstimatedFareHelper addStartFee() {
        totalFee = getDoubleValue(totalFee + billingWay.getStartFare(), 2);
        //添加明细
        costDetail.setStartFare(billingWay.getStartFare());
        costDetail.setStartTrip(billingWay.getStartTrip());
        costDetail.setStartDuration(billingWay.getStartDuration());
        return this;
    }

    /**
     * 添加等待费
     */
    public EstimatedFareHelper addWaitFee(Double waitFare) {
        totalFee = getDoubleValue(totalFee + waitFare, 2);
        return this;
    }

    /**
     * 添加时长费
     */
    public EstimatedFareHelper addTimeLengthFee() {
        //减去免费时长/分钟
        int beyondTime = planDuration - billingWay.getStartDuration();
        //没超过不处理
        if (beyondTime <= 0) {
            return this;
        }
        //时长费用
        double timeFee = getDoubleValue(beyondTime * billingWay.getBeyondTimeFare(), 1);
        //总费用
        totalFee = getDoubleValue(totalFee + timeFee, 2);

        //添加明细
        costDetail.setBeyondTimeLength(beyondTime);
        costDetail.setOverTimeFare(timeFee);
        return this;
    }


    /**
     * 添加里程费
     */
    public EstimatedFareHelper addMileageFee() {
        //减去起步里程
        double beyondMileages = getDoubleValue(getDoubleValue(planMileage, 2) - billingWay.getStartTrip(), 2);
        if (beyondMileages <= 0.0) {
            return this;
        }
        double beyondMileageFee = getDoubleValue(beyondMileages * billingWay.getBeyondTripFare(), 2);
        totalFee = getDoubleValue(totalFee + beyondMileageFee, 2);

        costDetail.setBeyondTrip(beyondMileages);
        costDetail.setOverTripFare(beyondMileageFee);
        return this;
    }

    /**
     * 添加夜间补贴
     */
    public EstimatedFareHelper addNightSubsidyFee() {
        //需要分段计费，不是按照出发时间点来算，按照出发时间-到达时间
        if (billingWay.getNightTimeStart() != null && billingWay.getNightTimeEnd() != null) {
            int nightMinutes = getNightMinutes();
            //含有夜间时长
            if (nightMinutes > 0) {
                double nightMileages = getDoubleValue(((nightMinutes / planDuration.doubleValue()) * planMileage), 2);
                double nightFee = getDoubleValue(nightMileages * billingWay.getNightTripFare(), 2);
                totalFee = getDoubleValue(totalFee + nightFee, 2);
                costDetail.setNightTrip(nightMileages);
                costDetail.setNightFare(nightFee);
            }
        }
        return this;
    }

    /**
     * 添加回空费用
     */
    public EstimatedFareHelper addHaulBackFee() {
        //实际总里程
        double mileages = planMileage;
        //超过这个里程就算回空
        double haulBackTrip = billingWay.getHaulBackTrip() == null ? 0 : billingWay.getHaulBackTrip();
        //回空单价价格
        double haulPrice = billingWay.getHaulBackTripFare() == null ? 0 : billingWay.getHaulBackTripFare();

        if (mileages <= haulBackTrip) {
            return this;
        }
        //回空总里程
        Double beyondHaulBackTrip = getDoubleValue(mileages - haulBackTrip, 2);
        Double haulBackFare = getDoubleValue(beyondHaulBackTrip * haulPrice, 2);
        totalFee = getDoubleValue(totalFee + haulBackFare, 2);
        costDetail.setHaulBackTrip(beyondHaulBackTrip);
        costDetail.setHaulBackFare(haulBackFare);
        return this;
    }

    /**
     * 添加高峰溢价
     */
    public EstimatedFareHelper addHighPremiumFee() {
        Double premiumRate = null;
        if (billingWay.getPremiumOneStart() != null && billingWay.getPremiumOneStart() != null) {
            if (isBetween(billingWay.getPremiumOneStart(), billingWay.getPremiumOneEnd())) {
                premiumRate = billingWay.getPremiumOneRate();
            }
        }
        if (billingWay.getPremiumTwoStart() != null && billingWay.getPremiumTwoEnd() != null) {
            if (isBetween(billingWay.getPremiumTwoStart(), billingWay.getPremiumTwoEnd())) {
                premiumRate = billingWay.getPremiumTwoRate();
            }
        }
        if (premiumRate != null) {
            Double premiumTotalFee = getDoubleValue(totalFee * premiumRate, 2);
            Double premiumFare = getDoubleValue(premiumTotalFee - totalFee, 2);
            totalFee = premiumTotalFee;
            costDetail.setHighPremiumRate(premiumRate);
            costDetail.setHighPremiumFare(premiumFare);
        }
        return this;
    }

    /**
     * 添加附加服务费
     */
    public EstimatedFareHelper addServiceFare(Double serviceFare) {
        if (serviceFare == null) {
            serviceFare = new Double(0);
        }
        //起步费
        totalFee = getDoubleValue(totalFee + serviceFare, 2);
        //添加明细
        costDetail.setServiceFare((costDetail.getServiceFare() == null ? 0 : costDetail.getServiceFare()) + serviceFare);
        return this;
    }


    private boolean isBetween(Date startTime, Date endTime) {
        Date date = new Date();
        return date.after(startTime) && date.before(endTime);
    }

    public static Double getDoubleValue(Double value, Integer digit) {
        if (digit <= 0d) {
            return 0d;
        }
        BigDecimal bd = BigDecimal.valueOf(value).setScale(digit, BigDecimal.ROUND_CEILING);
        return bd.doubleValue();
    }

    /**
     * 获取费用详情方法拿出来放在工具类里
     *
     * @return List<OrderCostItemVo>
     * @author Zerrion
     * @date 2017/12/20
     */
    public static List<OrderCostItemVo> trans2Items(OrderFareDto orderFareDto, Integer typeModule, Double assignDriverFee, Double tip, Double cancelFee, Double couponFare, Integer type, CommissionDto commissionDto) {
        Double startFare = 0d;
        Double overTripFare = 0d;
        Double overTimeFare = 0d;
        Double haulBackFare = 0d;
        Double nightFare = 0d;
        Double waitFare = 0d;
        Double highPremiumFare = 0d;
        Double actualFare = orderFareDto.getActualFare();
        Double serviceFare = orderFareDto.getServiceFare();
        Integer highwayFare = orderFareDto.getHighwayFare();
        Integer roadBridgeFare = orderFareDto.getRoadBridgeFare();
        Integer otherFare = orderFareDto.getOtherFare();
        if (type == 2) {
            if(orderFareDto.getStartFare() != null) {
                startFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getStartFare())).doubleValue();
            }
            if(orderFareDto.getOverTripFare() != null) {
                overTripFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getOverTripFare())).doubleValue();
            }
            if(orderFareDto.getOverTimeFare() != null) {
                overTimeFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getOverTimeFare())).doubleValue();
            }
            if(orderFareDto.getHaulBackFare() != null) {
                haulBackFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getHaulBackFare())).doubleValue();
            }
            if(orderFareDto.getNightFare() != null) {
                nightFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getNightFare())).doubleValue();
            }
            if(orderFareDto.getWaitFare() != null) {
                waitFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getWaitFare())).doubleValue();
            }
            if(orderFareDto.getHighPremiumFare() != null) {
                highPremiumFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(orderFareDto.getHighPremiumFare())).doubleValue();
            }
            Double other = 0d;
            if (actualFare != null) {
                if(cancelFee != null) {
                    actualFare = actualFare - cancelFee;
                    other = other + cancelFee;
                }
                if(tip != null) {
                    actualFare = actualFare - tip;
                    other = other + tip;
                }
                if(serviceFare != null) {
                    actualFare = actualFare - serviceFare;
                    other = other + serviceFare;
                }
                if(assignDriverFee != null) {
                    actualFare = actualFare - assignDriverFee;
                    other = other + assignDriverFee;
                }
                if(highwayFare != null) {
                    actualFare = actualFare - highwayFare;
                    other = other + highwayFare;
                }
                if(roadBridgeFare != null) {
                    actualFare = actualFare - roadBridgeFare;
                    other = other + roadBridgeFare;
                }
                if(otherFare != null) {
                    actualFare = actualFare - otherFare;
                    other = other + otherFare;
                }
                actualFare = commission(commissionDto.getPlatform(), commissionDto.getAgency(), commissionDto.getCompany(), BigDecimal.valueOf(actualFare)).doubleValue();
                actualFare = actualFare + other;
            }
        } else {
            startFare = orderFareDto.getStartFare();
            overTripFare = orderFareDto.getOverTripFare();
            overTimeFare = orderFareDto.getOverTimeFare();
            haulBackFare = orderFareDto.getHaulBackFare();
            nightFare = orderFareDto.getNightFare();
            waitFare = orderFareDto.getWaitFare();
            highPremiumFare = orderFareDto.getHighPremiumFare();
        }

        Double startTrip = orderFareDto.getStartTrip();
        Integer startDuration = orderFareDto.getStartDuration();
        Double beyondTrip = orderFareDto.getBeyondTrip();

        Integer beyondTimeLength = orderFareDto.getBeyondTimeLength();

        Double haulBackTrip = orderFareDto.getHaulBackTrip();

        Double nightTrip = orderFareDto.getNightTrip();

        Integer waitDuration = orderFareDto.getWaitDuration();

        Double highPremiumRate = orderFareDto.getHighPremiumRate();

        Double adjustFare = orderFareDto.getAdjustFare();

        Integer payType = orderFareDto.getPayType();
        BigDecimal orderFare = orderFareDto.getOrderFare();

        List<OrderCostItemVo> list = new ArrayList<>();
        int sort = 1;
        if (CommonConstant.BUSINESS_TYPE_TAXI == typeModule) {
            if (orderFare != null && orderFare.compareTo(BigDecimal.ZERO) > 0) {
                list.add(new OrderCostItemVo("订单金额", String.valueOf(EstimatedFareHelper.getDoubleValue(orderFare.doubleValue(), 2)), sort++, false));
            }
        }
        if (startFare != null && startFare > 0d) {
            list.add(new OrderCostItemVo((CommonConstant.BUSINESS_TYPE_TAXI == typeModule ? "打车费" : "起步费") + "(" + startTrip + "公里," + startDuration + "分钟)", String.valueOf(EstimatedFareHelper.getDoubleValue(startFare, 2)), sort++, false));
        }
        if (overTripFare != null && overTripFare > 0d) {
//            list.add(new OrderCostItemVo("超出里程费(" + EstimatedFareHelper.getDoubleValue(beyondTrip, 1) + "公里)", String.valueOf(EstimatedFareHelper.getDoubleValue(overTripFare, 1)), sort++, false));
            list.add(new OrderCostItemVo("超出里程费(" + EstimatedFareHelper.getDoubleValue(beyondTrip, 1) + "公里)", String.valueOf(EstimatedFareHelper.getDoubleValue(overTripFare, 2)), sort++, false));
        }
        if (overTimeFare != null && overTimeFare > 0d) {
            list.add(new OrderCostItemVo("超出时长费(" + beyondTimeLength + "分钟)", String.valueOf(EstimatedFareHelper.getDoubleValue(overTimeFare, 2)), sort++, false));
        }
        if (haulBackFare != null && haulBackFare > 0d) {
            list.add(new OrderCostItemVo("远途费(" + EstimatedFareHelper.getDoubleValue(haulBackTrip, 1) + "公里)", String.valueOf(EstimatedFareHelper.getDoubleValue(haulBackFare, 2)), sort++, false));
        }
        if (nightFare != null && nightFare > 0d) {
            list.add(new OrderCostItemVo("夜间补贴(" + EstimatedFareHelper.getDoubleValue(nightTrip, 1) + "公里)", String.valueOf(EstimatedFareHelper.getDoubleValue(nightFare, 2)), sort++, false));
        }
        if (waitFare != null && waitFare > 0d) {
            list.add(new OrderCostItemVo("超时等待费(" + waitDuration + "分钟)", String.valueOf(EstimatedFareHelper.getDoubleValue(waitFare, 2)), sort++, false));
        }
        if (highPremiumFare != null && highPremiumFare > 0d) {
            list.add(new OrderCostItemVo("高峰溢价费(" + highPremiumRate + "倍)", String.valueOf(EstimatedFareHelper.getDoubleValue(highPremiumFare, 2)), sort++, false));
        }
        if (cancelFee != null && cancelFee > 0d) {
            list.add(new OrderCostItemVo("取消费", String.valueOf(EstimatedFareHelper.getDoubleValue(cancelFee, 2)), sort++, false));
        }
        if (tip != null && tip > 0d) {
            list.add(new OrderCostItemVo("小费", String.valueOf(EstimatedFareHelper.getDoubleValue(tip, 2)), sort++, false));
        }
        if (serviceFare != null && serviceFare > 0d) {
            list.add(new OrderCostItemVo("附加服务费", String.valueOf(EstimatedFareHelper.getDoubleValue(serviceFare, 2)), sort++, false));
        }
        if (assignDriverFee != null && assignDriverFee > 0d) {
            list.add(new OrderCostItemVo("指定司机费", String.valueOf(EstimatedFareHelper.getDoubleValue(assignDriverFee, 2)), sort++, false));
        }
        if (highwayFare != null && highwayFare > 0) {
            list.add(new OrderCostItemVo("高速费", String.valueOf(EstimatedFareHelper.getDoubleValue(highwayFare.doubleValue(), 2)), sort++, false));
        }
        if (roadBridgeFare != null && roadBridgeFare > 0) {
            list.add(new OrderCostItemVo("路桥费", String.valueOf(EstimatedFareHelper.getDoubleValue(roadBridgeFare.doubleValue(), 2)), sort++, false));
        }
        if (otherFare != null && otherFare > 0) {
            list.add(new OrderCostItemVo("其他费用", String.valueOf(EstimatedFareHelper.getDoubleValue(otherFare.doubleValue(), 2)), sort++, false));
        }
        //符号根据具体数值来定
        if (adjustFare != null) {
            list.add(new OrderCostItemVo("费用调整", String.valueOf(EstimatedFareHelper.getDoubleValue(adjustFare, 2)), sort++, adjustFare < 0, true));
        }
        if (actualFare != null && actualFare > 0d) {
            String payTypeString = "";
            if (OrderConstant.PAY_TYPE_TENPAY == payType) {
                payTypeString = "微信支付";
            }
            if (OrderConstant.PAY_TYPE_ALIPAY == payType) {
                payTypeString = "支付宝支付";
            }
            if (OrderConstant.PAY_TYPE_CASH == payType) {
                payTypeString = "现金支付";
            }
            if (OrderConstant.PAY_TYPE_BALANCE == payType) {
                payTypeString = "余额支付";
            }
            if (OrderConstant.PAY_TYPE_COUPON == payType) {
                payTypeString = "优惠券抵扣支付";
            }
            if (OrderConstant.PAY_TYPE_CREDITCARD == payType) {
                payTypeString = "信用卡支付";
            }
            if (OrderConstant.PAY_TYPE_APPLEPAY == payType) {
                payTypeString = "ApplePay支付";
            }
            if (OrderConstant.PAY_TYPE_ZERO == payType) {
                payTypeString = "零元支付";
            }
            if (OrderConstant.PAY_TYPE_COMPANY_INNER == payType) {
                payTypeString = "企业内部支付";
            }
            list.add(new OrderCostItemVo(payTypeString, "-" + EstimatedFareHelper.getDoubleValue(actualFare, 2), sort++, true));
        }
        if ((couponFare != null && couponFare > 0d)) {
            list.add(new OrderCostItemVo("优惠券", "-" + EstimatedFareHelper.getDoubleValue(couponFare, 2), sort++, true));
        }
        return list;
    }


    /**
     * 获取夜间时长（单位：分钟）
     *
     * @author Zerrion
     */
    private int getNightMinutes() {
        Long startMinutes = billingWay.getNightTimeStart().getTime() / (1000 * 60);
        Long endMinutes = billingWay.getNightTimeEnd().getTime() / (1000 * 60);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(pointTime);
        String departTimeStr = calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":00";
        Long departMinutes = (Time.valueOf(departTimeStr).getTime()) / (1000 * 60);
        Long arrivedMinutes = departMinutes + planDuration;
        Long result = 0L;
        //夜间时间段 不跨天的情况
        if (startMinutes < endMinutes) {
            if (departMinutes < startMinutes && arrivedMinutes < startMinutes) {
                result = 0L;
            } else if (departMinutes < startMinutes && arrivedMinutes >= startMinutes && arrivedMinutes <= endMinutes) {
                result = arrivedMinutes - startMinutes;
            } else if (departMinutes < startMinutes && arrivedMinutes > endMinutes) {
                result = endMinutes - startMinutes;
            } else if (departMinutes >= startMinutes && arrivedMinutes <= endMinutes) {
                result = new Long(planDuration.intValue());
            } else if (departMinutes >= startMinutes && departMinutes <= endMinutes && arrivedMinutes > endMinutes) {
                result = endMinutes - departMinutes;
            } else {
                result = 0L;
            }
            //夜间时间段 跨天情况 e.g:23:00-5:00
        } else if (startMinutes > endMinutes) {
            //e.g:4:10-4:20
            if (departMinutes <= endMinutes && arrivedMinutes < endMinutes) {
                result = new Long(planDuration.intValue());
                //e.g:4:10-5:10
            } else if (departMinutes <= endMinutes && arrivedMinutes >= endMinutes && arrivedMinutes < startMinutes) {
                result = endMinutes - departMinutes;
                //e.g:4:10-23:10
            } else if (departMinutes <= endMinutes && arrivedMinutes >= startMinutes && arrivedMinutes <= (endMinutes + 24 * 60)) {
                result = endMinutes - departMinutes + arrivedMinutes - startMinutes;
                //e.g:5:10-5:20
            } else if (departMinutes > endMinutes && arrivedMinutes < startMinutes) {
                //e.g:5:10-23:10
            } else if (departMinutes > endMinutes && departMinutes <= startMinutes && arrivedMinutes >= startMinutes && arrivedMinutes <= (endMinutes + 24 * 60)) {
                result = arrivedMinutes - startMinutes;
                //e.g:22:00-6:00
            } else if (departMinutes > endMinutes && departMinutes <= startMinutes && arrivedMinutes > (endMinutes + 24 * 60)) {
                result = endMinutes + 24 * 60 - startMinutes;
                //23:10-23:20
            } else if (departMinutes >= startMinutes && departMinutes <= (endMinutes + 24 * 60) && arrivedMinutes <= (endMinutes + 24 * 60)) {
                result = new Long(planDuration.intValue());
            } else if (departMinutes >= startMinutes && departMinutes <= (endMinutes + 24 * 60) && arrivedMinutes > (endMinutes + 24 * 60) && arrivedMinutes < (startMinutes + 24 * 60)) {
                result = endMinutes + 24 * 60 - departMinutes;
            } else if (departMinutes >= startMinutes && departMinutes <= (endMinutes + 24 * 60) && arrivedMinutes > (endMinutes + 24 * 60) && arrivedMinutes >= (startMinutes + 24 * 60)) {
                result = endMinutes - departMinutes + arrivedMinutes - startMinutes;
            } else {
                result = 0L;
            }
        } else {//容错处理
            if (startMinutes >= departMinutes && startMinutes <= arrivedMinutes) {
                result = 1L;
            } else {
                result = 0L;
            }
        }
        return result.intValue();
    }

    /**
     * 获取费用详情方法拿出来放在工具类里
     *
     * @return List<OrderCostItemVo>
     * @author Zerrion
     * @date 2017/12/20
     */
    public static BigDecimal commission(SysBusinessOrganizationDto platform, SysBusinessOrganizationDto agency, SysBusinessOrganizationDto company, BigDecimal amount) {
        BigDecimal num = amount;
        if (platform != null && platform.getCommission() != null && platform.getCommission() > 0) {
            if (platform.getCommissionType() == 1) {//=1 按照百分比抽成
                amount = amount.subtract(num.multiply(BigDecimal.valueOf(platform.getCommission()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP))).setScale(2, RoundingMode.HALF_UP);
            } else if (platform.getCommissionType() == 2) {//=2 抽成固定金额
                amount = amount.subtract(BigDecimal.valueOf(platform.getCommission()));
            }
        }
        if (agency != null && agency.getCommission() != null && agency.getCommission() > 0) {
            if (agency.getCommissionType() == 1) {//=1 按照百分比抽成
                amount = amount.subtract(num.multiply(BigDecimal.valueOf(agency.getCommission()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP))).setScale(2, RoundingMode.HALF_UP);
            } else if (platform.getCommissionType() == 2) {//=2 抽成固定金额
                amount = amount.subtract(BigDecimal.valueOf(agency.getCommission()));
            }
        }
        if (company != null && company.getCommission() != null && company.getCommission() > 0) {
            if (company.getCommissionType() == 1) {//=1 按照百分比抽成
                amount = amount.subtract(num.multiply(BigDecimal.valueOf(company.getCommission()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP))).setScale(2, RoundingMode.HALF_UP);
            } else if (platform.getCommissionType() == 2) {//=2 抽成固定金额
                amount = amount.subtract(BigDecimal.valueOf(company.getCommission()));
            }
        }
        return amount;
    }
}
